

#ifndef RTREACTORREALTIMESIGNAL_H
#define RTREACTORREALTIMESIGNAL_H

#ifndef RT_LINUX
  #error ERROR: only LINUX supports realtime signal!
#endif // RT_LINUX

#include "RtReactorBase.h"
#include "RtReactorNotifyPipe.h"


#ifdef RT_ENABLE_CALENDAR_TIMER
  #include "RtTimerQueueCalendar.h"
#endif // RT_ENABLE_CALENDAR_TIMER

#include <sys/poll.h>
#include <linux/unistd.h>
#include <linux/types.h>
#include <linux/sysctl.h>

class CRtReactorRealTimeSignal : public CRtReactorBase  
{
public:
	CRtReactorRealTimeSignal();
	virtual ~CRtReactorRealTimeSignal();

	// interface IRtReactor
	virtual RtResult Open();

	virtual RtResult NotifyHandler(
		IRtEventHandler *aEh, 
		IRtEventHandler::MASK aMask);

	virtual RtResult RunEventLoop();

	virtual RtResult StopEventLoop();
	
	virtual RtResult Close();
	
protected:
	virtual RtResult OnHandleRegister(RT_HANDLE aFd, 
		IRtEventHandler::MASK aMask, IRtEventHandler *aEh);
	virtual void OnHandleRemoved(RT_HANDLE aFd);

	RtResult ProcessSignalOverFlow();
	RtResult ProcessOneSignalFd(int aFd, long int aBand);
	RtResult ProcessOneSignalQueue(int aVal);

protected:
	int SetProcRtsigMax_i(int aMaxNum);
	RtResult CheckPollIn_i(RT_HANDLE aFd, IRtEventHandler *aEh);
	RtResult Sigqueue_i(int aValue, BOOL aTrace = TRUE);

	// sig values.
	enum { 
		SV_NONE = 0, 
		SV_EVENT, 
		SV_STOP, 
		SV_TIMER 
	};
	static void TimerTickFun(int );

	sigset_t m_Sigset;
	int m_SigNum;
	CRtReactorNotifyPipe m_Notify;
	int m_nPid;
	BOOL m_bSignalOverFlowing;

#ifdef RT_ENABLE_CALENDAR_TIMER
	// interface IRtTimerQueue
	virtual RtResult ScheduleTimer(IRtTimerHandler *aTh, 
					  LPVOID aArg,
					  const CRtTimeValue &aInterval,
					  DWORD aCount);

	virtual RtResult CancelTimer(IRtTimerHandler *aTh);

	CRtTimerQueueCalendar m_CalendarTimer;
#endif // RT_ENABLE_CALENDAR_TIMER
};

#include <list>

// Buffer rt-signals in user space to increase efficience.
class CRtReactorRealTimeSignalBuffer : public CRtReactorRealTimeSignal
{
public:
	CRtReactorRealTimeSignalBuffer();
	virtual ~CRtReactorRealTimeSignalBuffer();

	// interface IRtReactor
	virtual RtResult Open();

	virtual RtResult RunEventLoop();
	
	virtual RtResult Close();

private:
	void InsertOneSigalNode_i(siginfo_t &aSigInfo);

public:
	class CSigalNode 
	{
	public:
		CSigalNode()
		{
			::memset(this, 0, sizeof(*this));
		}

		int m_si_code;
		union {
			int m_sival_int;

			struct {
				int m_si_fd;
				long int m_si_band;
				DWORD m_dwReadCount;
			} m_CodeIo;
		};
	};
	// We have to use list because <m_pSigalNodesIndex> will index it.
	typedef std::list<CSigalNode> SigalNodesType;

private:
	SigalNodesType m_SigalNodes;

	CSigalNode **m_pSigalNodesIndex;
	int m_nSigalNodeIndexNumber;
};


// inline functions
inline RtResult CRtReactorRealTimeSignal::Sigqueue_i(int aValue, BOOL aTrace)
{
	sigval svNew;
	svNew.sival_int = aValue;
	if (::sigqueue(m_nPid, m_SigNum, svNew) != 0) {
		if (aTrace) {
			RT_ERROR_TRACE("CRtReactorRealTimeSignal::Sigqueue_i, sigqueue() failed!"
				" err=" << errno << " aValue=" << aValue);
		}
		else {
			CRtTimeValue tvCur = CRtTimeValue::GetTimeOfDay();
			::printf("CRtReactorRealTimeSignal::Sigqueue_i, sigqueue() failed!"
				" err=%d sec=%ld usec=%d.\n", errno, tvCur.GetSec(), tvCur.GetUsec());
		}
		return RT_ERROR_FAILURE;
	}
	else
		return RT_OK;
}


#endif // !RTREACTORREALTIMESIGNAL_H
